package com.yonyou.pmclouds.measureindex.service.rmiimpl;

import com.alibaba.dubbo.config.annotation.Service;
import com.yonyou.pmclouds.ApplicationConsts;
import com.yonyou.pmclouds.basecom.bp.processor.AuditInfoInsertMultiProcessor;
import com.yonyou.pmclouds.basecom.bp.processor.AuditInfoInsertProcessor;
import com.yonyou.pmclouds.basecom.bp.processor.AuditInfoUpdateProcessor;
import com.yonyou.pmclouds.basecom.bp.template.MultiInsertBpTemplate;
import com.yonyou.pmclouds.basecom.bp.template.SingleDeleteBpTemplate;
import com.yonyou.pmclouds.basecom.bp.template.SingleInsertBpTemplate;
import com.yonyou.pmclouds.basecom.bp.template.SingleUpdateBpTemplate;
import com.yonyou.pmclouds.basecom.consts.EnableStatusConst;
import com.yonyou.pmclouds.basecom.entity.PageObject;
import com.yonyou.pmclouds.basecom.exception.BusinessException;
import com.yonyou.pmclouds.basecom.runtime.RuntimeEnvironment;
import com.yonyou.pmclouds.basecom.util.CommonProgramConsts;
import com.yonyou.pmclouds.measureindex.entity.MeasureIndexVO;
import com.yonyou.pmclouds.measureindex.mapper.MeasureIndexMapper;
import com.yonyou.pmclouds.measureindex.processor.CheckMeasureIndexRefProcessor;
import com.yonyou.pmclouds.measureindex.processor.MeasureIndexNameAndCodeCheck;
import com.yonyou.pmclouds.measureindex.processor.MultiAddNameAndCodeCheck;
import com.yonyou.pmclouds.measureindex.service.rmiitf.MeasureIndexService;
import com.yonyou.pmclouds.plan.planindex.entity.PlanIndexVO;
import com.yonyou.pmclouds.plan.planindex.mapper.PlanIndexMapper;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.misc.Hash;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

@Service(version = ApplicationConsts.APPLICATION_VERSION, interfaceClass = MeasureIndexService.class)
public class MesureIndexServiceImpl implements MeasureIndexService {

    private static final String[] UPDATE_FIELDS = {MeasureIndexVO.CODE, MeasureIndexVO.NAME, MeasureIndexVO.MEMO
            , MeasureIndexVO.ENABLE_STATUS, MeasureIndexVO.UNIT};
    @Autowired
    private MeasureIndexMapper measureIndexMapper;
    @Autowired
    private PlanIndexMapper planIndexMapper;

    @Override
    public PageObject<MeasureIndexVO> queryMeasureIndexByPage(String timestamp, String keyword, int start, int offset, int enableStatus) {
        if (offset > CommonProgramConsts.DEFAULT_MAX_QUERY_SIZE) {
            offset = CommonProgramConsts.DEFAULT_MAX_QUERY_SIZE;
        }
        if (offset < CommonProgramConsts.DEFAULT_MIN_QUERY_SIZE) {
            offset = CommonProgramConsts.DEFAULT_MIN_QUERY_SIZE;
        }
        String[] keywords = null;
        keyword = StringUtils.trim(keyword);
        if (!StringUtils.isEmpty(keyword)) {
            keywords = StringUtils.split(keyword, ' ');
            if (ArrayUtils.isEmpty(keywords)) {
                keywords = null;
            } else {
                keywords = ArrayUtils.subarray(keywords, 0, 3);
            }

        }

        String pkTenant = RuntimeEnvironment.getTenantId();

        int sum = measureIndexMapper.countMeasureIndexByTimeStamp(timestamp, keywords, enableStatus, pkTenant);
        MeasureIndexVO[] measureIndexVOS = measureIndexMapper.selectMeasureIndexByPage(timestamp, keywords, start, offset, enableStatus, pkTenant);

        PageObject<MeasureIndexVO> result = new PageObject<>(measureIndexVOS, sum, start);
        return result;
    }

    @Override
    public MeasureIndexVO add(MeasureIndexVO measureIndexVO) throws BusinessException {


        measureIndexVO.setPkTenant(RuntimeEnvironment.getTenantId());
        SingleInsertBpTemplate<MeasureIndexVO> bp = new SingleInsertBpTemplate<MeasureIndexVO>(measureIndexMapper);

        bp.addBeforeProcessor(new MeasureIndexNameAndCodeCheck(measureIndexMapper));
        //添加审计信息
        bp.addBeforeProcessor(new AuditInfoInsertProcessor<MeasureIndexVO>());

        MeasureIndexVO result = bp.insert(measureIndexVO);

        return result;
    }

    @Override
    public MeasureIndexVO modify(MeasureIndexVO measureIndexVO) throws BusinessException {

        SingleUpdateBpTemplate<MeasureIndexVO> bp = new SingleUpdateBpTemplate<>(measureIndexMapper, UPDATE_FIELDS);

        bp.addBeforeProcessor(new MeasureIndexNameAndCodeCheck(measureIndexMapper));
        //添加审计信息
        bp.addBeforeProcessor(new AuditInfoUpdateProcessor<MeasureIndexVO>());
        MeasureIndexVO result = bp.update(measureIndexVO);
        return result;
    }

    @Override
    public MeasureIndexVO modifyStatus(MeasureIndexVO measureIndexVO) throws BusinessException {
        SingleUpdateBpTemplate<MeasureIndexVO> bp = new SingleUpdateBpTemplate<>(measureIndexMapper, new String[]{EnableStatusConst.ENABLE_STATUS});

        bp.addBeforeProcessor(new AuditInfoUpdateProcessor<MeasureIndexVO>());
        MeasureIndexVO result = bp.update(measureIndexVO);
        return result;

    }

    @Override
    public String delete(MeasureIndexVO measureIndexVO) throws BusinessException {

        SingleDeleteBpTemplate<MeasureIndexVO> bp = new SingleDeleteBpTemplate<>(measureIndexMapper);
        bp.addBeforeProcessor(new CheckMeasureIndexRefProcessor(planIndexMapper));
        MeasureIndexVO result = bp.delete(measureIndexVO);
        return result.getPkMeasureindex();
    }

    @Override
    public MeasureIndexVO[] addMeasureIndexVOS(MeasureIndexVO[] vos) throws BusinessException {

        MultiInsertBpTemplate<MeasureIndexVO> bp = new MultiInsertBpTemplate<MeasureIndexVO>(measureIndexMapper);

        bp.addBeforeProcessor(new MultiAddNameAndCodeCheck(measureIndexMapper));
        bp.addBeforeProcessor(new AuditInfoInsertMultiProcessor<MeasureIndexVO>());

        MeasureIndexVO[] result = bp.insert(vos);

        return result;
    }

    @Override
    public Map<String, Object> saveAddAndUpdate(MeasureIndexVO[] vos) throws BusinessException {

        String tenantId = RuntimeEnvironment.getTenantId();

        ArrayList<MeasureIndexVO> addList = new ArrayList<>();
        ArrayList<MeasureIndexVO> updateList = new ArrayList<>();
        ArrayList<MeasureIndexVO> deleteList = new ArrayList<>();
        for (MeasureIndexVO vo : vos) {
            vo.setPkTenant(tenantId);
            if (StringUtils.isEmpty(vo.getPkMeasureindex())) {
                addList.add(vo);
            } else if(EnableStatusConst.ENABLE == vo.getDr()){
                deleteList.add(vo);
            }else{
                updateList.add(vo);
            }
        }

        /**
         *   1.在添加和修改之前进行唯一校验
         *   2.在修改和删除之前进行关联统计
         */
        ArrayList<MeasureIndexVO> data = new ArrayList<>();
        data.addAll(updateList);
        data.addAll(addList);
        nameAndCodeUniqueCheck(data);

        ArrayList<MeasureIndexVO> result = new ArrayList<>();
        if (addList != null && !addList.isEmpty()) {
            //批量添加
            MultiInsertBpTemplate<MeasureIndexVO> bp = new MultiInsertBpTemplate<>(measureIndexMapper);
            bp.addBeforeProcessor(new AuditInfoInsertMultiProcessor<MeasureIndexVO>());
            MeasureIndexVO[] measureIndexVOS = bp.insert(addList.toArray(new MeasureIndexVO[addList.size()]));
            result.addAll(Arrays.asList(measureIndexVOS));
        }

        String updateMessage = getRefDataMessage(updateList);
        //批量修改
        for (MeasureIndexVO measureIndexVO : updateList) {
            SingleUpdateBpTemplate<MeasureIndexVO> updateBp = new SingleUpdateBpTemplate<>(measureIndexMapper, UPDATE_FIELDS);
            updateBp.addBeforeProcessor(new AuditInfoUpdateProcessor<MeasureIndexVO>());
            MeasureIndexVO vo = updateBp.update(measureIndexVO);
            result.add(vo);
        }

        String delMessage = getRefDataMessage(deleteList);//会把删除中关联的数据从集合中剔除
       //批量删除

        for (MeasureIndexVO vo : deleteList) {
            SingleDeleteBpTemplate<MeasureIndexVO> delBp = new SingleDeleteBpTemplate<>(measureIndexMapper);
            delBp.delete(vo);
        }

        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("measureIndexVOS",result.toArray(new MeasureIndexVO[result.size()]));
        resultMap.put("message",updateMessage+delMessage);
        return resultMap;
    }

    public void nameAndCodeUniqueCheck(List<MeasureIndexVO> data) throws BusinessException {
        /**
         *  1.将数据拆分成 code 和 name的 set 集合
         *  2.根据code和name查询所有重合的MeasureIndex数据
         *  3.将重合数据按照 code 和 name 添加至map
         *  4.判断name和code重合的对象
         *   判断逻辑：
         *     1.判断名字和编码全部一样
         * 	      1.1 判断名字和编码是否是本对象
         * 		  1.2 判断名字是否是本对象
         * 		  1.3 判断编码是否是本对象
         * 	2.判断名字一样
         * 	      2.1 判断名字是否是本对象
         * 	3.判断编码一样
         * 	      3.1 判断编码是否是本对象
         */

        if(data == null || data.isEmpty()) return;
        HashSet<String> codeSet = new HashSet<>();
        HashSet<String> nameSet = new HashSet<>();

        for (MeasureIndexVO measureIndexVO : data) {
            codeSet.add(measureIndexVO.getCode());
            nameSet.add(measureIndexVO.getName());
        }

        MeasureIndexVO[] vos = measureIndexMapper.queryMeasureIndexByNameAndCode(codeSet, nameSet,RuntimeEnvironment.getTenantId());

        HashMap<String, MeasureIndexVO> codeMap = new HashMap<>();
        HashMap<String, MeasureIndexVO> nameMap = new HashMap<>();

        for (MeasureIndexVO vo : vos) {
            codeMap.put(vo.getCode(), vo);
            nameMap.put(vo.getName(), vo);
        }

        StringBuffer finalMessage = new StringBuffer();

        String codeMessage = "编码:%s重复\n";
        String nameMessage = "名称:%s重复\n";
        String codeAndNameMessage = "编码:%s,名称:%s重复\n";


        for (MeasureIndexVO measureIndexVO : data) {
            String code = measureIndexVO.getCode();
            String name = measureIndexVO.getName();

            if (codeMap.containsKey(code) && nameMap.containsKey(name)) {
                //判断是否是修改的对象
                if (measureIndexVO.getPkMeasureindex() != null && codeMap.get(code) != null) {
                    boolean codeCheck = measureIndexVO.getPkMeasureindex().equals(codeMap.get(code).getPkMeasureindex());
                    boolean nameCheck = measureIndexVO.getPkMeasureindex().equals(nameMap.get(name).getPkMeasureindex());
                    if (codeCheck && nameCheck) continue;
                    if (nameCheck) {
                        //名称跟自己重复
                        finalMessage.append(String.format(new String(codeMessage),code));
                        continue;
                    }
                    if (codeCheck) {
                        //编码跟自己重复
                        finalMessage.append(String.format(new String(nameMessage),name));
                        continue;
                    }
                }
                finalMessage.append(String.format(new String(codeAndNameMessage), code, name));
                continue;
            }
            if (codeMap.containsKey(code)) {
                if(measureIndexVO.getPkMeasureindex() != null && codeMap.get(code) != null){
                    if(measureIndexVO.getPkMeasureindex().equals(codeMap.get(code).getPkMeasureindex())) continue;
                }
                finalMessage.append(String.format(new String(codeMessage),code));
                continue;
            } else {
                codeMap.put(code, null);
            }
            if (nameMap.containsKey(name)) {
                if(measureIndexVO.getPkMeasureindex() != null && nameMap.get(name) != null){
                    if(measureIndexVO.getPkMeasureindex().equals(nameMap.get(name).getPkMeasureindex())) continue;
                }

                finalMessage.append(String.format(new String(nameMessage),name));
                continue;
            } else {
                nameMap.put(name, null);
            }
        }

        if(finalMessage.length() > 0) throw new BusinessException(finalMessage.toString());
    }

    public String getRefDataMessage(List<MeasureIndexVO> measureIndexVOS){
        /**
         *  1.构建 measureIndex 集合 查询关联数据
         *  2.将数据与measureIndex 映射到map
         *  3.将重复的数据添加到 repeatPks的集合中
         *  4.校验
         */
        if(measureIndexVOS == null || measureIndexVOS.isEmpty()) return "";
        HashSet<String> pkMeasureindexs = new HashSet<>();
        HashMap<String, MeasureIndexVO> dataMap = new HashMap<>();
        for (MeasureIndexVO measureIndexVO : measureIndexVOS) {
            pkMeasureindexs.add(measureIndexVO.getPkMeasureindex());
            dataMap.put(measureIndexVO.getPkMeasureindex(),measureIndexVO);
        }

        PlanIndexVO[] planIndexVOS = planIndexMapper.queryIdnexByPkMeasureindex(pkMeasureindexs);
        StringBuffer finalMessage = new StringBuffer();

        if(planIndexVOS != null && planIndexVOS.length != 0) {
            String delMessage = "%s、%s被引用，无法删除。\n";
            String updMessage = "您所修改的%s、%s数据已影响历史数据。\n";
            HashSet<String> repeatPks = new HashSet<>();
            for (PlanIndexVO planIndexVO : planIndexVOS) {
                repeatPks.add(planIndexVO.getPkMeasureIndex());
            }
            for (String pkMeasureIndex : dataMap.keySet()) {
                if(repeatPks.contains(pkMeasureIndex)){
                    //重复数据
                    MeasureIndexVO vo = dataMap.get(pkMeasureIndex);
                    if(EnableStatusConst.ENABLE == vo.getDr()){
                        measureIndexVOS.remove(vo);
                        finalMessage.append(String.format(new String(delMessage),vo.getCode(),vo.getName()));
                    }else{
                        finalMessage.append(String.format(new String(updMessage),vo.getCode(),vo.getName()));
                    }
                }
            }
        }
        return finalMessage.toString();

    }
}
